﻿using System;

namespace Course1
{
    /// <summary>
    /// 类的基本结构（重点掌握实列成员和静态成员并且理解）
    /// 1.完整限定名：命名空间.类型名或实列名.静态函数或者实列函数（限定也是面向对象的一大特点）
    /// 2.类中的成员：静态成员（静态字段、静态属性、静态函数），实列成员（实列字段、实列属性、实列函数）
    /// 3.静态成员的特点：类似c语言里面的全局变量，只不过被限定在类里了，由于没有this因此不能直接访问实列成员（注意静态成员全局只有一份）
    /// 4.实列成员：实列成员必须得有实列才能调用，在类外部必须得有实列才能调用，在类内部有this才能调用
    /// </summary>
    public class Example2
    {
        /// <summary>
        /// 静态字段
        /// </summary>
        public static double pi = 3.1415;
        /// <summary>
        /// 静态属性
        /// </summary>
        public static double Pi { get { return pi; } }
       
        /// <summary>
        /// 实列字段
        /// 字段特点：
        /// 1.建议私有化
        /// 2.建议已下划线开头
        /// 3.字段有默认值，默认值规律（安全考虑）：
        ///      数字类型：0
        ///      char类型：0
        ///      布尔类型：false
        ///      引用类型：null
        /// </summary>
        private int _age;
        /// <summary>
        /// 实列属性
        /// 1.属性建议公开
        /// 2.属性用于保护字段
        /// 3.属性建议首字母大写
        /// 4.属性本质就是方法（具体可以反编译，编译器帮你做了转换，让你像使用字段一样进行read\write操作）
        /// 5.在属性内部不能调用本属性，防止递归
        /// </summary>
        public int Age
        {
            get
            {
                return _age;
            }
            set
            {
                if (_age < 0)
                {
                    throw new Exception("年龄不能小于0");
                }
                _age = value;//value就是右值
            }
        }
        /// <summary>
        /// 实列字段-默认
        /// </summary>
        private int gender;
        /// <summary>
        /// 实列构造器
        /// 1.用于初始化字段（当然也可以是属性）
        /// 2.每个类都有一个默认的无参数构造器
        /// 3.构造器没有返回值（实际返回的是这个对象的的指针），名字是类名
        /// 4.构造器里有this，泛指当前对象（当前对象的指针）
        /// </summary>
        public Example2()
        {

        }
        /// <summary>
        /// 实列字段-带参
        /// </summary>
        /// <param name="age"></param>
        /// <param name="gender"></param>
        public Example2(int age, int gender)
        {
            _age = age;//对字段复制，会跳过属性的检查，建议对属性赋值（除非你想跳过检查）
            this.gender = gender;//当局部变量或者参数与字段或者属性重名可以通过this区分
            //gender = gender;//就近原则
            //Age = age;
        }
        /***
         * 静态构造器，
         * 一个类只能有一个，没有访问修饰符号，没有参数
         * 在类加载（用到的）的时候执行，并且只执行一次
         */
        static Example2()
        {
            
        }
        /// <summary>
        /// 实列函数
        /// 1.每个实列函数内部都有一个this，泛指当前对象（当前对象的指针）
        /// 2.this可以省略，除非局部变量和字段或者属性重名
        /// 3.可以理解成实列函数的第一个参数是this
        /// </summary>
        public void DoSome1()
        {
            Console.WriteLine("我的年龄是：" + Age);
            Console.WriteLine("我的年龄是：" + this.Age);
        }
        /// <summary>
        /// 函数重载
        /// 1.在类的内部、函数名相同的，参数的个数或者类型不同的函数之间（缺一不可）
        /// 2.函数名相同的，并且参数的个数和类型都相同但是返回值不同的也不属于重载（不存在，因为无法编译通过，讨论无法通过编译的代码没有意义）
        /// </summary>
        /// <param name="age"></param>
        public void DoSome1(int age)
        {
            Console.WriteLine("我的年龄是：" + age);
            Console.WriteLine("我的年龄是：" + Age);
            Console.WriteLine("我的年龄是：" + this.Age);
        }
        /// <summary>
        /// 实列函数
        /// 1.实列函数可以拥有n个
        /// 2.实列方法之间可以相互调用
        /// 3.实列方法可以调用静态函数（静态函数是全局函数）
        /// </summary>
        public void DoSome2()
        {
            DoSome1();//调用实列函数
            this.DoSome1();//完整写法,DoSome1的this和DoSome2的this是同一个this
            DoSome3();//调用静态函数
            Example2.DoSome3();//完整写法
            Console.WriteLine(Pi);//调用静态变量
            Console.WriteLine(Example2.Pi);//完整写法，在类的内部可以省略类名
        }
        /// <summary>
        /// 静态函数（类函数，全局函数）
        /// 1.类函数中没有this,无法访问实列成员（字段，属性，实列方法）
        /// 2.一般用于工具类使用
        /// 3.静态函数特点和c语言里面的全局变量类型，只不过限定这类里面了，因为C#要求方法必须定义在class中
        /// </summary>
        public static void DoSome3()
        {
            //由于没有this不能直接访问实列成员，但是可以创建一个实列来间接访问
            var obj = new Example2();
            Console.WriteLine(obj.Age);
            obj.DoSome2();
            obj.DoSome1();
            Console.WriteLine("这是一个Example类");
        }
        public static void DoSome3(Example2 obj)
        {
            //由于没有this不能直接访问实列成员，但是可以创建一个实列参数来间接访问
            //可以假设DoSome3可以方法实列函数会怎么样？（答，如果这个实列函数使用了实列变量，但是静态函数中没有，那this的指的谁呢？）
            Console.WriteLine(obj.Age);
            obj.DoSome2();
            obj.DoSome1();
            Console.WriteLine("这是一个Example类");
        }
    }


    class Example2Test
    {
        public void Test()
        {

            /**
             * 调用无参数构造器实列化对象，
             *  在堆中创建内存保存数据成员，无论创建多少个对象函数只有一份，函数保存在代码区
             *  函数中的参数和局部变量也要等到调用的那一刻在创建
             */
            var obj1 = new Example2();//只有调用test函数的时候才创建，调用的时候才执行new
            //访问类静态数据成员
            Console.WriteLine(Example2.Pi);//必须加上类型名进行限定
            //访问静态函数成员函数
            Example2.DoSome3();
        }
    }

}
